package com.jin.webvideo.util.sys;

import com.jin.webvideo.base.util.ByteArray;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.brotli.dec.BrotliInputStream;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ClientUtil {
    private static CloseableHttpClient client;
    private static CookieStore cookieStore;
    private static final RequestConfig requestConfig;

    static {
        cookieStore = new BasicCookieStore();
        RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
        client = HttpClients.custom().setDefaultRequestConfig(globalConfig).setDefaultCookieStore(cookieStore).build();
        requestConfig = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(10000).build();
    }

    public static String getCookie(String domain, String path, String name){
        List<Cookie> cookies = cookieStore.getCookies();
        for (Cookie cookie : cookies){
            if (domain.equals(cookie.getDomain()) && path.equals(cookie.getPath()) && name.equals(cookie.getName()) ){
                return cookie.getValue();
            }
        }
        return "";
    }
    public static void setCookie(Cookie cookie) {
        cookieStore.addCookie(cookie);
    }
    public static String httpPost(String url, Map<String,String> header, String payload) throws IOException {
        InputStream inputStream = httpPost(url, header, new StringEntity(payload), null);
        String content = toString(inputStream);
        if (inputStream != null){
            inputStream.close();
        }
        return content;
    }
    public static String httpPost(String url, Map<String,String> header, Map<String,String> paramters) throws IOException {
        InputStream inputStream = httpPost(url, header, paramters, null);
        String content = toString(inputStream);
        inputStream.close();
        return content;
    }
    public static InputStream httpPost(String url, Map<String,String> header, Map<String,String> paramters, RequestConfig config) throws IOException {
        HttpEntity entity = null;
        if (null != paramters && !paramters.isEmpty()){
            List<NameValuePair> list = new ArrayList<>();
            for (String key : paramters.keySet()){
                list.add(new BasicNameValuePair(key, paramters.get(key)));
            }
            entity = new UrlEncodedFormEntity(list);
        }
        return httpPost(url, header, entity, config);
    }

    public static InputStream httpPost(String url, Map<String,String> header, HttpEntity entity, RequestConfig config) throws IOException {
        HttpPost post = new HttpPost(url);
        requestInit(post, header, config);
        if (null != entity){
            post.setEntity(entity);
        }
        return requestAutoRelease(post);
    }
    public static String httpGet(String url) throws IOException {
        return httpGet(url, null);
    }
    public static String httpGet(String url, Map<String,String> headMap) throws IOException {
        InputStream inputStream = httpGet(url, headMap, null);
        String content = toString(inputStream);
        inputStream.close();
        return content;
    }
    public static InputStream httpGet(String url, Map<String,String> headers, RequestConfig config) throws IOException {
        HttpGet httpGet = new HttpGet(url);
        requestInit(httpGet, headers, config);
        return requestAutoRelease(httpGet);
    }


    private static void requestInit(HttpRequestBase base, Map<String,String> headers, RequestConfig config){
        base.setHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36 Edg/103.0.1264.44");
        base.setHeader("Accept-Encoding", "gzip, deflate, br");
        base.setHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
        if (null != headers && !headers.isEmpty()){
            for (String key : headers.keySet()){
                base.setHeader(key, headers.get(key));
            }
        }
        if (config == null){
            config = requestConfig;
        }
        base.setConfig(config);
    }

    public static InputStream requestAutoRelease(HttpRequestBase httpGet) throws IOException {
        InputStream inputStream = null;
        String msg = null;
        try {
            CloseableHttpResponse response = httpRequest(httpGet);
            HttpEntity entity = response.getEntity();
            if (null != entity ){
                InputStream stream = entity.getContent();
                if (null != entity.getContentEncoding() && "br".equals(entity.getContentEncoding().getValue())){
                    stream = new BrotliInputStream(stream);
                }
                inputStream = output2input(inpu2output(stream));
                stream.close();
            }
            response.close();
        }
        catch (IOException e){
            msg = e.getMessage();
        }
        httpGet.releaseConnection();
        if (null != msg){
            throw new IOException(msg);
        }
        return inputStream;
    }
    public static CloseableHttpResponse execute(HttpUriRequest http) throws IOException {
        return client.execute(http);
    }
    public static CloseableHttpResponse httpRequest(HttpUriRequest httpGet) throws IOException {
        CloseableHttpResponse response = client.execute(httpGet);
        if (response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 206){
            return response;
        }
        response.close();
        throw new IOException(response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
    }

    public static InputStream output2input(ByteArrayOutputStream out) throws IOException {
        return new ByteArrayInputStream(out.toByteArray());
    }

    public static ByteArrayOutputStream inpu2output(InputStream stream) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        write(stream, outputStream);
        return outputStream;
    }
    public static void write(InputStream inputStream, OutputStream outputStream) throws IOException {
        byte[] bs = new byte[1024];
        int len = -1;
        while ( (len = inputStream.read(bs)) != -1 ){
            outputStream.write(bs,0, len);
        }
        outputStream.flush();
    }
    public static String toString(InputStream stream) throws IOException {
        if (stream == null){
            return "";
        }
        ByteArray byteArray = new ByteArray();
        byte[] bs = new byte[1024];
        int len = -1;
        while ( (len = stream.read(bs)) != -1 ){
            byteArray.append(bs, 0, len);
        }
        return new String(byteArray.toArray());
    }
}
